/*
 * Copyright (C) 2012  Mingye Cheng <Cheng, Mingye at GMAIL>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * References:
 * 	http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/beans.html
 * 		4.6.2 ApplicationContextAware and BeanNameAware
 * 		4.10.1 @Component and further stereotype annotations
 * 	http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
 * 		11.5.6 Using @Transactional
 * 
 * Libraries:
 * 	org.springframework.beans-X.X.X.RELEASE.jar
 * 	org.springframework.context-X.X.X.RELEASE.jar
 * 	org.springframework.core-X.X.X.RELEASE.jar
 */
package com.iiiss.ssh.impl.daos;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.annotation.Transactional;

import com.iiiss.ssh.core.entities.BaseEntity;

@Transactional
public class BaseDaoImpl implements ApplicationContextAware {

	@PersistenceContext
	protected EntityManager entityManager;

	protected ApplicationContext applicationContext;

	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}

	protected <T extends BaseEntity> T createPersistedEntity(String beanName, Class<T> clazz) {
		T entity = applicationContext.getBean(beanName, clazz);
		entityManager.persist(entity);
		return entity;
	}

	@SuppressWarnings("unchecked")
	private <T extends BaseEntity> Class<T> getImplClass(String beanName, Class<T> clazz) {
		return (Class<T>) applicationContext.getBean(beanName, clazz).getClass();
	}

	protected <T extends BaseEntity> T findEntity(String beanName, Class<T> clazz, Long id) {
		Class<T> implClass = this.getImplClass(beanName, clazz);
		return entityManager.find(implClass, id);
	}

	protected <T extends BaseEntity> T findEntity(String beanName, Class<T> clazz) {
		return this.findEntity(beanName, clazz, "", new Object[] {});
	}

	protected <T extends BaseEntity> T findEntity(String beanName, Class<T> clazz, String where) {
		return this.findEntity(beanName, clazz, where, new Object[] {});
	}

	protected <T extends BaseEntity> T findEntity(String beanName, Class<T> clazz, String where,
			Object[] parameters) {
		List<T> entities = this.findEntities(beanName, clazz, where, parameters);
		if (!entities.isEmpty())
			return entities.get(0);
		else
			return null;
	}

	protected <T extends BaseEntity> List<T> findEntities(String beanName, Class<T> clazz) {
		return this.findEntities(beanName, clazz, "", new Object[] {});
	}

	protected <T extends BaseEntity> List<T> findEntities(String beanName, Class<T> clazz,
			String where) {
		return this.findEntities(beanName, clazz, where, new Object[] {});
	}

	@SuppressWarnings("unchecked")
	protected <T extends BaseEntity> List<T> findEntities(String beanName, Class<T> clazz,
			String where, Object[] parameters) {
		Class<T> implClass = this.getImplClass(beanName, clazz);
		String queryString = "SELECT e FROM " + implClass.getName() + " e " + where;
		Query query = entityManager.createQuery(queryString);
		for (int i = 0; i < parameters.length; i++)
			query.setParameter(i + 1, parameters[i]);
		List<T> entities = query.getResultList();
		return entities;
	}

}
